﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using AMM.Model;
using AMM.Model.Business;

namespace AMM.DataAccess.Business {
    public class CustomerOrderRepository : BaseRepository<CustomerOrder> {

        private int _pageSize;

        public CustomerOrderRepository(int pageSize) {
            this._pageSize = pageSize;
        }

        public CustomerOrder FetchCustomerOrderById(int customerOrderId) {
            using (var ctx = this.Context) {
                return ctx.CustomerOrders
                    .Include("CustomerOrderDetails")
                    .FirstOrDefault(x => x.CustomerOrderId == customerOrderId);
            }
        }

        public CustomerOrder FetchCustomerOrderByIdForView(int customerOrderId) {
            using (var ctx = this.Context) {
                return ctx.CustomerOrders
                    .Include("CustomerOrderDetails")
                    .Include("CustomerOrderDetails.Product")
                    .FirstOrDefault(x => x.CustomerOrderId == customerOrderId);
            }
        }
        
        public void UpdateCustomerOrder(CustomerOrder customerOrder, CustomerOrder oldCustomerOrder) {
            using (var ctx = this.Context) {
                using (DbContextTransaction trans = ctx.Database.BeginTransaction()) {
                    try {
                        customerOrder.CustomerOrderDetails.Where(x => x.ClassStatus == ClassStatus.Added).ToList().ForEach(x => {
                            x.CustomerOrder = customerOrder;
                            x.CustomerOrderId = customerOrder.CustomerOrderId;
                            x.CustomerOrderDetailsId = Guid.NewGuid().GetHashCode();
                        });
                        if (oldCustomerOrder.AttachmentId.HasValue) {
                            Attachment oldAttachment = ctx.Attachments.Find(oldCustomerOrder.AttachmentId);
                            oldAttachment.IsLinked = false;
                            ctx.Attachments.Attach(oldAttachment);
                            ctx.Entry(oldAttachment).State = EntityState.Modified;
                        }
                        if (customerOrder.AttachmentId.HasValue) {
                            Attachment newAttachment = ctx.Attachments.Find(customerOrder.AttachmentId);
                            newAttachment.IsLinked = true;
                            ctx.Attachments.Attach(newAttachment);
                            ctx.Entry(newAttachment).State = EntityState.Modified;
                        }
                        // do not try to merge with above codes, because you can't change the fields which was marked as primary key
                        customerOrder.CustomerOrderDetails.ToList().ForEach(x => {
                            ctx.CustomerOrderDetails.Attach(x);
                            switch (x.ClassStatus) {
                                case ClassStatus.UnChanged:
                                    ctx.CustomerOrderDetails.Attach(x);
                                    ctx.Entry(x).State = EntityState.Unchanged;
                                    break;
                                case ClassStatus.Updated:
                                    x.ModifiedBy = customerOrder.ModifiedBy;
                                    x.ModifiedDatetime = DateTime.Now;
                                    ctx.CustomerOrderDetails.Attach(x);
                                    ctx.Entry(x).State = EntityState.Modified;
                                    break;
                                case ClassStatus.Added:
                                    x.CreatedBy = customerOrder.ModifiedBy;
                                    x.CreatedDatetime = DateTime.Now;
                                    ctx.CustomerOrderDetails.Attach(x);
                                    ctx.Entry(x).State = EntityState.Added;
                                    break;
                                case ClassStatus.Deleted:
                                    ctx.CustomerOrderDetails.Attach(x);
                                    ctx.Entry(x).State = EntityState.Deleted;
                                    break;
                            }
                        });

                        ctx.CustomerOrders.Attach(customerOrder);
                        ctx.Entry(customerOrder).State = EntityState.Modified;
                        ctx.SaveChanges();
                        trans.Commit();
                    }
                    catch (Exception ex) {
                        trans.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void DeleteMultipleCustomerOrder(params int[] customerOrderIds) {
            using (var ctx = this.Context) {
                using (DbContextTransaction trans = ctx.Database.BeginTransaction()) {
                    try {
                        ctx.CustomerOrderDetails.Where(x => customerOrderIds.Contains(x.CustomerOrderId)).ToList().ForEach(x => {
                            ctx.CustomerOrderDetails.Remove(x);
                        });
                        ctx.CustomerOrders.Where(x => customerOrderIds.Contains(x.CustomerOrderId)).ToList().ForEach(x => {
                            ctx.CustomerOrders.Remove(x);
                        });
                        ctx.SaveChanges();
                        trans.Commit();
                    }
                    catch (Exception ex) {
                        trans.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public List<CustomerOrder> FetchCustomerOrderList(CustomerOrderSearchModel searchModel, int pageIndex) {
            using (var ctx = this.Context) {
                var query = ctx.CustomerOrders
                    .Include("Customer")
                    .Include("Basic")
                    .Include("Basic1")
                    .Include("Basic2")
                    .Where(x => !string.IsNullOrEmpty(x.OrderNo));

                if (!string.IsNullOrEmpty(searchModel.OrderNo)) {
                    query = query.Where(x => x.OrderNo.Contains(searchModel.OrderNo));
                }
                if (!string.IsNullOrEmpty(searchModel.CustomerCode)) {
                    query = query.Where(x => x.Customer.Code.Contains(searchModel.CustomerCode));
                }
                if (!string.IsNullOrEmpty(searchModel.CustomerName)) {
                    query = query.Where(x => x.Customer.Name.Contains(searchModel.CustomerName));
                }
                if (searchModel.OrderDateStart.HasValue) {
                    query = query.Where(x => x.OrderDate >= DbFunctions.TruncateTime(searchModel.OrderDateStart.Value));
                }
                if (searchModel.OrderDateEnd.HasValue) {
                    query = query.Where(x => x.OrderDate <= DbFunctions.TruncateTime(searchModel.OrderDateEnd.Value));
                }
                if (searchModel.DeliverDateStart.HasValue) {
                    query = query.Where(x => x.DeliverDate >= DbFunctions.TruncateTime(searchModel.DeliverDateStart.Value));
                }
                if (searchModel.DeliverDateEnd.HasValue) {
                    query = query.Where(x => x.DeliverDate <= DbFunctions.TruncateTime(searchModel.DeliverDateEnd.Value));
                }
                if (searchModel.PayCurrencyId.HasValue) {
                    query = query.Where(x => x.Basic.BasicsId == searchModel.PayCurrencyId.Value);
                }
                if (searchModel.PaymentTypeId.HasValue) {
                    query = query.Where(x => x.Basic1.BasicsId == searchModel.PaymentTypeId.Value);
                }
                if (searchModel.OrderTypeId.HasValue) {
                    query = query.Where(x => x.Basic2.BasicsId == searchModel.OrderTypeId.Value);
                }

                searchModel.Records = query.Count();
                pageIndex = (pageIndex - 1) * this._pageSize > searchModel.Records ? 1 : pageIndex;

                return query.OrderByDescending(x => x.CreatedDatetime).Skip((pageIndex - 1) * this._pageSize).Take(this._pageSize).ToList();
            }
        }
    }
}
